//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
///
///
//==================================================================

#include "stdafx.h"
#include "m5d_types.h"
#include "m5d_utils_ext.h"
#include "m5d_verts.h"

//==================================================================
using namespace M5D;
using namespace PSYSGFX;

//==================================================================
const float *MultiVerts::GetWeiR() const
{
	AssertLockR();

	if ( _max_bones_per_vertex <= 0 )
		return NULL;

	int	expected_len = _pos_vertsp.size() * _max_bones_per_vertex;

	if ( _wei_vertsp.size() != expected_len )
	{
		throw "no good !";
	}

	return &_wei_vertsp.front();
}

//==================================================================
float *MultiVerts::GetWeiW()
{
	AssertLockW();

	if ( _max_bones_per_vertex <= 0 )
		return NULL;

	int	expected_len = _pos_vertsp.size() * _max_bones_per_vertex;

	if ( _wei_vertsp.size() != expected_len )
	{
		_wei_vertsp.resize( expected_len );
		onChange();
	}

	return &_wei_vertsp.front();
}

//==================================================================
const u_char *MultiVerts::GetBNLR() const
{
	AssertLockR();

	if ( _max_bones_per_vertex <= 0 )
		return NULL;

	int	expected_len = _pos_vertsp.size() * _max_bones_per_vertex;

	if ( _bni_vertsp.size() != expected_len )
	{
		throw "no good !";
	}

	return &_bni_vertsp.front();	// $$$ why front ?!
}

//==================================================================
u_char *MultiVerts::GetBNLW()
{
	AssertLockW();

	if ( _max_bones_per_vertex <= 0 )
		return NULL;

	int	expected_len = _pos_vertsp.size() * _max_bones_per_vertex;

	if ( _bni_vertsp.size() != expected_len )
	{
		_bni_vertsp.resize( expected_len );
		onChange();
	}

	return &_bni_vertsp.front();	// $$$ why front ?!
}

//==================================================================
Vector3 *MultiVerts::AddPosN( int add_n )
{
	AssertLockW();
	
	size_t	idx = _pos_vertsp.size();
	_pos_vertsp.resize( idx + add_n );
	
	return &_pos_vertsp[idx];
}
//==================================================================
Vector2 *MultiVerts::AddTexN( int add_n )
{
	AssertLockW();

	size_t	idx = _tex_vertsp.size();
	_tex_vertsp.resize( idx + add_n );
	
	return &_tex_vertsp[idx];
}
//==================================================================
Color4b *MultiVerts::AddColN( int add_n )
{
	AssertLockW();

	size_t	idx = _col_vertsp.size();
	_col_vertsp.resize( idx + add_n );

	return &_col_vertsp[idx];
}
//==================================================================
Vector3 *MultiVerts::AddNorN( int add_n )
{
	AssertLockW();

	size_t	idx = _nor_vertsp.size();
	_nor_vertsp.resize( idx + add_n );

	return &_nor_vertsp[idx];
}

//==================================================================
void MultiVerts::SetPosN( int set_n )
{
	AssertLockW();
	_pos_vertsp.resize( set_n );
}
//==================================================================
void MultiVerts::SetTexN( int set_n )
{
	AssertLockW();
	_tex_vertsp.resize( set_n );
}
//==================================================================
void MultiVerts::SetColN( int set_n )
{
	AssertLockW();
	_col_vertsp.resize( set_n );
}
//==================================================================
void MultiVerts::SetNorN( int set_n )
{
	AssertLockW();
	_nor_vertsp.resize( set_n );
}

//============================================================================
void MultiVerts::SetWeightsMax( int max_weights_per_vertex ) throw(...)
{
	AssertLockW();

	// can only set once for now
	PASSERT( _max_bones_per_vertex == 0 || _max_bones_per_vertex == max_weights_per_vertex );
	PASSERT( max_weights_per_vertex <= 4 );

	_max_bones_per_vertex = max_weights_per_vertex;

	if ( _max_bones_per_vertex > 0 )
	{
		_wei_vertsp.resize( _pos_vertsp.size() * _max_bones_per_vertex );
		_bni_vertsp.resize( _pos_vertsp.size() * _max_bones_per_vertex );
	}
}

//==================================================================
void MultiVerts::TransPos( const int *tablep ) throw(...)
{
	int	bpv	= _max_bones_per_vertex;
	int	nv	= _pos_vertsp.size();

	if ( nv <= 0 )
		return;

	// largest buffer actually required
	u_char	*tbuffp;
	if NOT( tbuffp = (u_char *)PSYS_MALLOC( nv * sizeof(float) * M5D_MAX_BONES_PER_VERTEX ) )
	{
		throw "Not enough memory !";
	}

	if ( _pos_vertsp.size() ) TransArray( (u_char *)&_pos_vertsp.front(), tbuffp, sizeof(_pos_vertsp[0]), tablep, nv );
	if ( _bni_vertsp.size() ) TransArray( (u_char *)&_bni_vertsp.front(), tbuffp, sizeof(_bni_vertsp[0])*bpv, tablep, nv );
	if ( _wei_vertsp.size() ) TransArray( (u_char *)&_wei_vertsp.front(), tbuffp, sizeof(_wei_vertsp[0])*bpv, tablep, nv );

	SAFE_FREE( tbuffp );	  

	onChange();
}

//==================================================================
void MultiVerts::CopyFrom( const MultiVerts &src ) throw(...)
{
	int	bpv	= src._max_bones_per_vertex;
	try {
		SetWeightsMax( bpv );

		_pos_vertsp.resize( src._pos_vertsp.size() );
		_tex_vertsp.resize( src._tex_vertsp.size() );
		_col_vertsp.resize( src._col_vertsp.size() );
		_nor_vertsp.resize( src._nor_vertsp.size() );
		_wei_vertsp.resize( src._wei_vertsp.size() );
		_bni_vertsp.resize( src._bni_vertsp.size() );

		std::copy( src._pos_vertsp.begin(), src._pos_vertsp.end(), _pos_vertsp.begin() );
		std::copy( src._tex_vertsp.begin(), src._tex_vertsp.end(), _tex_vertsp.begin() );
		std::copy( src._col_vertsp.begin(), src._col_vertsp.end(), _col_vertsp.begin() );
		std::copy( src._nor_vertsp.begin(), src._nor_vertsp.end(), _nor_vertsp.begin() );
		std::copy( src._wei_vertsp.begin(), src._wei_vertsp.end(), _wei_vertsp.begin() );
		std::copy( src._bni_vertsp.begin(), src._bni_vertsp.end(), _bni_vertsp.begin() );
		/*
		_pos_vertsp.clone( src._pos_vertsp );
		_tex_vertsp.clone( src._tex_vertsp );
		_col_vertsp.clone( src._col_vertsp );
		_nor_vertsp.clone( src._nor_vertsp );
		_wei_vertsp.clone( src._wei_vertsp );
		_bni_vertsp.clone( src._bni_vertsp );
		*/
	} catch (...) {
		_pos_vertsp.clear();	// do we actually free ?
		_tex_vertsp.clear();
		_col_vertsp.clear();
		_nor_vertsp.clear();
		_bni_vertsp.clear();
		_wei_vertsp.clear();
		throw "CopyFrom Failed !";
	}

	onChange();
}
